#pragma once

#include "Socket.hpp"
#include "Epoll.hpp"
#include "Connection.hpp"

#include <queue>

class Reactor
{
    static const int default_wait_max_size = 64; // 调用一次epoll_wait最多可以获取多少个就绪fd
    static const int default_timeout = -1;       // 阻塞式

    static const uint64_t default_timeout_period = 30; // 默认超时时间是30秒

    typedef function<string(string &)> HandleRequset_t; // 处理接收缓冲区中的数据的方法

    class Compare
    {
    public:
        bool operator()(shared_ptr<Connection> left, shared_ptr<Connection> right)
        {
            if (left->Timestamp() > right->Timestamp())
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    };

public:
    Reactor()
        : _handle(nullptr)
    {
        _epoll.Init();
    }

    bool isValid(int fd)
    {
        if (_connections.find(fd) == _connections.end())
        {
            return false;
        }
        return true;
    }

    bool InsetConnection(int fd, shared_ptr<Connection> connection)
    {
        if (isValid(fd))
        {
            return false;
        }
        // 插入新连接
        _connections.insert({fd, connection});

        // 添加到epoll模型中进行关心
        if (!_epoll.Add(fd, connection->Event()))
        {
            return false;
        }

        return true;
    }

    void Loop() // 派发就绪事件
    {
        int n = _epoll.Wait(_events, default_wait_max_size, default_timeout);
        if (n > 0)
        {
            LOG(LogLevel::DEBUG) << n << "个fd就绪";

            for (int i = 0; i < n; i++)
            {
                // 取出就绪fd和其就绪事件
                int ready_fd = _events[i].data.fd;
                uint32_t ready_events = _events[i].events;

                if (ready_events & EPOLLERR || ready_events & EPOLLHUP)
                {
                    LOG(LogLevel::DEBUG) << "fd: " << ready_fd << "异常事件就绪";

                    // 异常事件转读写事件
                    ready_events = (EPOLLIN | EPOLLOUT);
                }
                else if (ready_events & EPOLLIN)
                {
                    LOG(LogLevel::DEBUG) << "fd: " << ready_fd << "读事件就绪";

                    if (isValid(ready_fd)) // 判断连接是否非法
                    {
                        _connections[ready_fd]->Recver();
                    }
                    else
                    {
                        LOG(LogLevel::DEBUG) << "fd: " << ready_fd << "非法连接(fd)";
                    }
                }
                else if (ready_events & EPOLLOUT)
                {
                    LOG(LogLevel::DEBUG) << "fd: " << ready_fd << "写事件就绪";

                    if (isValid(ready_fd)) // 判断连接是否非法
                    {
                        _connections[ready_fd]->Sender();
                    }
                    else
                    {
                        LOG(LogLevel::DEBUG) << "fd: " << ready_fd << "非法连接(fd)";
                    }
                }
            }
        }
        else if (n == 0)
        {
            LOG(LogLevel::DEBUG) << "没有fd就绪";
        }
        else
        {
            LOG(LogLevel::WARNING) << "epoll_wait error";
        }
    }
    bool DleteConnection(int fd)
    {
        if (!isValid(fd)) // 如果连接不存在，就没必要删除
        {
            return false;
        }
        if (!_epoll.Delete(fd))
        {
            return false;
        }
        _connections.erase(fd);

        LOG(LogLevel::DEBUG) << "关闭sockfd: " << fd;
        return true;
    }
    bool ModifyEvent(int fd, uint32_t event)
    {
        if (!isValid(fd)) // 如果连接不存在，就修改不了
        {
            return false;
        }

        // 如果要修改的时间本来就一样，就直接返回
        //    减少系统调用的次数
        if (_connections[fd]->Event() == event)
        {
            return true;
        }

        // 修改关心事件
        if (!_epoll.Modify(fd, event))
        {
            return false;
        }
        _connections[fd]->SetEvent(event);
        return true;
    }
    void Register(HandleRequset_t handle)
    {
        _handle = handle;
    }
    HandleRequset_t HandleRequset()
    {
        return _handle;
    }

    bool PushTimestamp(int fd, shared_ptr<Connection> connection)
    {
        if (!isValid(fd)) // 如果连接不存在,则表示连接非法，不可插入
        {
            return false;
        }
        // 只有合法连接才需要超时管理
        _timeout.push(connection);
        return true;
    }
    void TimeOut() // 超时淘汰
    {
        uint64_t cur = ::time(nullptr); // 获取当前时间戳

        // 获取最不活跃的堆顶连接，最后一次活跃的时间戳
        if (_timeout.empty())
        {
            return;
        }
        uint64_t farthest = (_timeout.top())->Timestamp();

        while (cur - farthest > default_timeout_period)
        {
            int sockfd = _timeout.top()->Fd();

            // 删除超时连接
            DleteConnection(sockfd);
            _timeout.pop();

            LOG(LogLevel::DEBUG) << "删除超时连接,sockfd: " << sockfd;

            // 更新，判断下一个堆顶连接是否超时
            if (_timeout.empty())
            {
                break;
            }
            farthest = (_timeout.top())->Timestamp();
        }
    }

    bool Start()
    {
        if (_isrunning == true)
        {
            return false;
        }
        _isrunning = true;
        while (_isrunning)
        {
            Loop();    // 事件派发
            TimeOut(); // 超时管理
        }
        _isrunning = false;

        return true;
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~Reactor()
    {
    }

private:
    Epoller _epoll;                                          // epoll模型
    unordered_map<int, shared_ptr<Connection>> _connections; // 管理所有连接，以fd为key
    struct epoll_event _events[default_wait_max_size];       // 用于获取就绪fd
    HandleRequset_t _handle;                                 // 处理接收缓冲区中的数据的方法
    bool _isrunning;
    priority_queue<shared_ptr<Connection>, vector<shared_ptr<Connection>>, Compare> _timeout; // 以Connection的成员变量_timestamp为key的小堆，用于超时管理
};